using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Admin.NET.Application.Entity.Business;
using Admin.NET.Application.EventBus;
using Admin.NET.Application.Excel;
using Admin.NET.Application.Service.Payment.Dto;
using Admin.NET.Core;
using Furion;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.EventBus;
using Furion.FriendlyException;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Yitter.IdGenerator;

namespace Admin.NET.Application;

/// <summary>
/// 支付记录服务
/// </summary>
[ApiDescriptionSettings(new string[] { "业务应用" }, Order = 100)]
public class PaymentService : IDynamicApiController, ITransient, IPrivateDependency
{
	private readonly SqlSugarRepository<PaymentRecord> _rep;

	private readonly SqlSugarRepository<RoomBalanceRecord> _balanceRep;

	private readonly RoomService _roomService;

	private readonly UserManager _userManager;

	public PaymentService(SqlSugarRepository<PaymentRecord> rep, RoomService roomService, UserManager userManager, SqlSugarRepository<RoomBalanceRecord> balanceRep)
	{
		_rep = rep;
		_roomService = roomService;
		_userManager = userManager;
		_balanceRep = balanceRep;
	}

	[HttpPost("/payment/billflowPayExecl")]
	public async Task<IActionResult> BillflowPayExecl([FromBody] PaymentInput input)
	{
		string str = "账单流水-" + DateTime.Now.ToString("yyyy-MM-dd");
		List<string> column = new List<string>();
		List<string> title = new List<string>();
		ISugarQueryable<PaymentRecord> query = _rep.Context.Queryable<PaymentRecord>().WhereIF(!string.IsNullOrWhiteSpace(input.OutTradeNo), (PaymentRecord u) => u.OutTradeNo.Contains(input.OutTradeNo.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.PaymentName), (PaymentRecord u) => u.PaymentName.Contains(input.PaymentName.Trim()))
			.WhereIF(!string.IsNullOrWhiteSpace(input.Remark), (PaymentRecord u) => u.Remark.Contains(input.Remark.Trim()))
			.WhereIF(input.RoomId.HasValue, (PaymentRecord u) => u.RoomId == input.RoomId)
			.WhereIF(input.PayType.HasValue, (PaymentRecord u) => (int?)u.PayType == (int?)input.PayType)
			.WhereIF(input.StartTime.HasValue && input.EndTime.HasValue, (PaymentRecord u) => u.CreateTime >= input.StartTime && u.CreateTime <= input.EndTime)
			.OrderBy((PaymentRecord u) => u.CreateTime, OrderByType.Desc);
		query = query.OrderBuilder(input);
		List<PaymentOutput> list = await query.Select((PaymentRecord u) => new PaymentOutput
		{
			Amount = u.Amount,
			PayType = u.PayType,
			BeforeAmount = u.BeforeAmount,
			BillRecordId = u.BillRecordId,
			Body = u.Body,
			BuyerId = u.BuyerId,
			BuyerPayAmount = u.BuyerPayAmount,
			CreateTime = u.CreateTime,
			CreateUserId = u.CreateUserId,
			CreateUserName = u.CreateUserName,
			Id = u.Id,
			IsDeductBalance = u.IsDeductBalance,
			IsDelete = u.IsDelete,
			IsDrawABill = u.IsDrawABill,
			IsPay = u.IsPay,
			NotifyTime = u.NotifyTime,
			OutTradeNo = u.OutTradeNo,
			PaymentName = u.PaymentName,
			ReceiptAmount = u.ReceiptAmount,
			Remark = u.Remark,
			RoomId = u.RoomId,
			RoomName = from r in SqlFunc.Subqueryable<Room>()
				where (long?)r.Id == u.RoomId
				select r.Name,
			Subject = u.Subject,
			TenantId = u.TenantId,
			TradeNo = u.TradeNo,
			TradeStatus = u.TradeStatus,
			UpdateTime = u.UpdateTime,
			UpdateUserId = u.UpdateUserId
		}).ToListAsync();
		column.AddRange(new string[9] { "OutTradeNo", "PaymentName", "IsPay", "RoomName", "Amount", "ReceiptAmount", "PayType", "CreateTime", "Remark" });
		title.AddRange(new string[9] { "商家订单号", "名称", "支付结果", "房间", "余额(￥)", "实收(￥)", "支付类型", "订单时间", "备注" });
		Dictionary<string, Dictionary<string, string>> dic = new Dictionary<string, Dictionary<string, string>>
		{
			{
				"IsPay",
				new Dictionary<string, string>
				{
					{ "0", "待支付" },
					{ "1", "已支付" },
					{ "2", "已关闭" },
					{ "3", "账单异常" },
					{ "4", "退款" }
				}
			},
			{
				"PayType",
				new Dictionary<string, string>
				{
					{ "0", "线下支付" },
					{ "1", "微信支付" },
					{ "2", "对公支付" }
				}
			}
		};
		MemoryStream memery = ExportToExcel.ExportToList(list.ToArray(), str, str, column.ToArray(), title.ToArray());
		App.HttpContext.Response.ContentType = "application/vnd.ms-excel";
		byte[] aa = memery.ToArray();
		return new FileStreamResult(new MemoryStream(aa), "application/octet-stream")
		{
			FileDownloadName = str + ".xlsx"
		};
	}

	/// <summary>
	/// 分页查询支付记录
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/payment/page")]
	public async Task<dynamic> Page([FromQuery] PaymentInput input)
	{
		ISugarQueryable<PaymentRecord> query = _rep.Context.Queryable<PaymentRecord>().WhereIF(!string.IsNullOrWhiteSpace(input.OutTradeNo), (PaymentRecord u) => u.OutTradeNo.Contains(input.OutTradeNo.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.PaymentName), (PaymentRecord u) => u.PaymentName.Contains(input.PaymentName.Trim()))
			.WhereIF(!string.IsNullOrWhiteSpace(input.Remark), (PaymentRecord u) => u.Remark.Contains(input.Remark.Trim()))
			.WhereIF(input.RoomId.HasValue, (PaymentRecord u) => u.RoomId == input.RoomId)
			.WhereIF(input.PayType.HasValue, (PaymentRecord u) => (int?)u.PayType == (int?)input.PayType)
			.WhereIF(input.StartTime.HasValue && input.EndTime.HasValue, (PaymentRecord u) => u.CreateTime >= input.StartTime && u.CreateTime <= input.EndTime)
			.OrderBy((PaymentRecord u) => u.CreateTime, OrderByType.Desc);
		query = query.OrderBuilder(input);
		return await query.Select((PaymentRecord u) => new PaymentOutput
		{
			Amount = u.Amount,
			PayType = u.PayType,
			BeforeAmount = u.BeforeAmount,
			BillRecordId = u.BillRecordId,
			Body = u.Body,
			BuyerId = u.BuyerId,
			BuyerPayAmount = u.BuyerPayAmount,
			CreateTime = u.CreateTime,
			CreateUserId = u.CreateUserId,
			CreateUserName = u.CreateUserName,
			Id = u.Id,
			IsDeductBalance = u.IsDeductBalance,
			IsDelete = u.IsDelete,
			IsDrawABill = u.IsDrawABill,
			IsPay = u.IsPay,
			NotifyTime = u.NotifyTime,
			OutTradeNo = u.OutTradeNo,
			PaymentName = u.PaymentName,
			ReceiptAmount = u.ReceiptAmount,
			Remark = u.Remark,
			RoomId = u.RoomId,
			RoomName = from r in SqlFunc.Subqueryable<Room>()
				where (long?)r.Id == u.RoomId
				select r.Name,
			Subject = u.Subject,
			TenantId = u.TenantId,
			TradeNo = u.TradeNo,
			TradeStatus = u.TradeStatus,
			UpdateTime = u.UpdateTime,
			UpdateUserId = u.UpdateUserId
		}).ToPagedListAsync(input.Page, input.PageSize);
	}

	/// <summary>
	/// 线下充值
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/payment/offlineAdd")]
	public async Task Add(AddPaymentInput input)
	{
		try
		{
			await _rep.Context.Ado.BeginTranAsync();
			await _balanceRep.Context.Ado.BeginTranAsync();
			var balance = await (from w in _rep.Context.Queryable<Room>()
				where (long?)w.Id == input.RoomId
				select w into s
				select new { s.Balance, s.OwnerId, s.BuildingId }).FirstAsync();
			decimal amount = Math.Abs(input.Amount);
			if (balance == null)
			{
				throw Oops.Bah("房间不存在或已被删除，请刷新后重试");
			}
			long tenantId = _userManager.TenantId;
			PaymentRecord record = new PaymentRecord
			{
				Id = YitIdHelper.NextId(),
				BeforeAmount = balance.Balance,
				CreateUserName = App.User.FindFirst("RealName").Value,
				IsPay = input.IsPay.Value,
				PaymentName = "线下充值",
				PayType = PayTypeEnum.线下,
				RoomId = input.RoomId,
				Remark = input.Remark,
				Subject = "线下充值",
				OwnerId = balance.OwnerId,
				BuildingId = balance.BuildingId
			};
			if (input.IsPay.GetValueOrDefault() == 1)
			{
				record.Amount = amount;
				record.IsGiveAsAPresent = input.IsGiveAsAPresent.GetValueOrDefault();
				if (input.ReceiptAmount.HasValue && !input.IsGiveAsAPresent.GetValueOrDefault())
				{
					record.ReceiptAmount = Math.Abs(input.ReceiptAmount.Value);
				}
				IUpdateable<Room> tmp = _rep.Context.Updateable<Room>();
				tmp = tmp.SetColumns((Room s) => new Room
				{
					Balance = s.Balance + amount,
					LatestWarningBalance = null
				});
				await tmp.Where((Room w) => (long?)w.Id == input.RoomId).ExecuteCommandAsync();
				if (record.Amount != 0m)
				{
					await _roomService.AddRoomBalanceRecord(_balanceRep.Context, input.RoomId.Value, record.Id, 0, record.Amount, tenantId, "线下充值");
				}
			}
			else
			{
				if (input.IsPay.GetValueOrDefault() != 4)
				{
					throw Oops.Bah("未定义");
				}
				record.Amount = -amount;
				if (input.ReceiptAmount.HasValue)
				{
					record.ReceiptAmount = -Math.Abs(input.ReceiptAmount.Value);
				}
				record.PaymentName = "线下退款";
				record.Subject = "线下退款";
				record.IsDeductBalance = true;
				IUpdateable<Room> tmp = _rep.Context.Updateable<Room>();
				tmp = tmp.SetColumns((Room s) => new Room
				{
					Balance = s.Balance - amount
				});
				await tmp.Where((Room w) => (long?)w.Id == input.RoomId).ExecuteCommandAsync();
				if (record.Amount != 0m)
				{
					await _roomService.AddRoomBalanceRecord(_balanceRep.Context, input.RoomId.Value, record.Id, 0, record.Amount, tenantId, "线下退款");
				}
			}
			await _rep.InsertAsync(record);
			await _rep.Context.Ado.CommitTranAsync();
			await _balanceRep.Context.Ado.CommitTranAsync();
			if (input.IsPay.GetValueOrDefault() == 1)
			{
				try
				{
					EventPayload payload2 = new EventPayload
					{
						Data = record.RoomId.ToString(),
						TenantId = tenantId
					};
					await MessageCenter.PublishAsync("SwitchOnGate", payload2);
				}
				catch (Exception)
				{
				}
			}
		}
		catch (Exception ex)
		{
			await _rep.Context.Ado.RollbackTranAsync();
			await _balanceRep.Context.Ado.RollbackTranAsync();
			throw ex;
		}
	}

	/// <summary>
	/// 获取充值记录详情
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/payment/detail")]
	public async Task<PaymentRecord> Get([FromQuery] QueryePaymentInput input)
	{
		return await _rep.GetFirstAsync((PaymentRecord u) => u.Id == input.Id);
	}

	/// <summary>
	/// 获取充值记录列表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/payment/list")]
	public async Task<dynamic> List([FromQuery] PaymentInput input)
	{
		return await _rep.AsQueryable().ToListAsync();
	}
}
